package com.suiwei.base;

import org.junit.jupiter.api.Test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;import java.util.Calendar;
import java.util.Date;
import java.util.Set;
/**
 * @author suiwei
 * @date 2023/4/9 20:42
 */
// jdk8之前：Date，SimpleDateFormat，Calendar
// 都是可变对象；线程不安全；只能精确到毫秒
// jdk8之后：
// 都是不可变对象，修改后会返回新的时间对象，不会丢失最开始的时间；线程安全；可以精确到纳秒

public class TImeDemo {
  @Test
  void test() {
    // 获取1970年1月1日0时0分0秒到现在所经历过的毫秒值
    System.out.println(System.currentTimeMillis());
  }
  // Date类；时间类；导包一定是java.util包下的
  @Test
  void testDate() {
    Date date1 = new Date(); // 空参构造：将当前时间封装成Date日期对象
    Date date2 = new Date(1000L); // 带long类型构造：把时间戳转换成Date日期对象
    long time = date1.getTime(); // 返回时间戳
    date1.setTime(1000L); // 跟new Date(1000L)效果一样
    System.out.println(date1);
  }

  // SimpleDateFormat类：格式化类；
  @Test
  void testSimpleDateFormat() throws ParseException {

    Date now = new Date();
    SimpleDateFormat sdf1 = new SimpleDateFormat(); // 空参构造方法，调用默认格式
    System.out.println(sdf1.format(now)); // 23-5-29 下午8:25
    SimpleDateFormat sdf2 = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
    System.out.println(sdf2.format(now)); // Date格式化成字符串
    String today = "20230529 12:12:12";
    System.out.println(sdf2.parse(today)); // 字符串解析成Date
  }

  // Calendar类：日历类；代表的是系统此刻时间对应的日历，通过它可以单独获取、修改时间中的年月日时分秒等
  // get；set；add；方法
  @Test
  void testCalendar() {

    Calendar cal = Calendar.getInstance(); // 获取日历类的对象；是抽象类，不能直接创建对象；可以调用getInstance静态方法获取子类对象
    System.out.println(cal.get(1)); // get方法需要一个int类型的值（1代表年，2代表月），返回一个int类型的值
    System.out.println(cal.get(Calendar.YEAR)); // 数字不好记，推荐使用类中的静态常量
    System.out.println(cal.get(Calendar.MONTH) + 1); // 月份0-11，从0开始，需要加1得到真实的月份
    System.out.println(cal.get(Calendar.DAY_OF_MONTH)); // 获取日
    System.out.println(
        cal.get(Calendar.DAY_OF_WEEK)); // 获取星期几，返回的比实际大1；返回的是1-7，对应国外的日-六；实际使用的时候要提现写一个星期的数组

    // set：修改日历的字段信息
    cal.set(Calendar.YEAR, 2008);
    System.out.println(cal.get(Calendar.YEAR));
    cal.set(2010, 10, 10); // 2010-11-10（注意月份）
    System.out.println(cal.getTime());

    // add：对某个字段增加/减少指定的值
    cal.add(Calendar.YEAR, 5);
    System.out.println(cal.getTime());

    // Date--Calendar互相转换
    // Calendar转成Date
    Date time = cal.getTime();
    System.out.println(time); // 获取Date类型的时间
    // Date转成Calendar
    Date now = new Date();
    cal.setTime(now);
    System.out.println(cal.getTime());
  }

  // --------------------------------------------------------jdk8之后的版本---------------------------------------------------------

  // 日历类：localDate；localTime;localDateTime
  @Test
  void testCalendarNew() {
    // 代表本地日期：年月日星期
    LocalDate.now(); // 获取当前日期
    LocalDate.of(2022, 12, 12); // 设置指定日期
    // 代表本地时间：时分秒纳秒
    LocalTime.now();
    LocalTime.of(12, 12, 12, 12);
    // 代表本地日期时间
    LocalDateTime now = LocalDateTime.now(); // 获取当前时间
    LocalDateTime of = LocalDateTime.of(2008, 11, 11, 12, 12, 12); // 获取指定的时间
    // 转换
    now.toLocalDate();
    now.toLocalTime();
    // 获取
    System.out.println(now.getMonth()); // 返回一个月份对象；july
    System.out.println(now.getMonthValue()); // 返回一个int数字；表示的就是本月，不需要再加1
    System.out.println(now.getDayOfMonth()); // 这个月的几号
    System.out.println(now.getDayOfWeek().getValue()); // 返回DayOfWeek对象，再次调用getValue才是返回int数值
    // 修改；都是不可变对象，修改后会返回新的时间对象，不会丢失最开始的时间
    System.out.println("------修改-----");
    System.out.println(now.withHour(1)); // 把时间设置为1点，返回一个新对象，原来的now不变；wiht只能修改一个值，不能整体做修改；整体修改用of
    System.out.println(now.minusDays(1)); // 把时间减一天
    System.out.println(now.plusDays(1)); // 时间加一天
    // 比较
    System.out.println("------比较-----");
    System.out.println(now.isAfter(now.plusDays(2))); // false
    System.out.println(now.isBefore(now.plusDays(2))); // true
    System.out.println(now.equals(now.plusDays(2))); // false
  }
  // 日期格式化类：DateTimeFormatter；用于时间的格式化和解析
  @Test
  void testFormatNew() {
    LocalDateTime now = LocalDateTime.now();
    // 获取格式化对象
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
    // 格式化：时间对象-->字符串
    String format = formatter.format(now);
    // 解析：字符串-->时间对象
    String today = "20231212";
    LocalDate parse = LocalDate.parse(today, formatter);
  }
  // 时间类：Instant；ZoneId；ZonedDateTime；
  @Test
  void testTimeNew() {
    //  Instant：时间戳；表示时间的对象，类似于Date；不带时区
    // Instant.now()使用的是UTC时间（协调世界时）；北京时间与UTC的时差为+8，也就是UTC+8。
    // LocalDate、LocalDateTime 的now()方法使用的是系统默认时区，不存在Instant.now()的时间问题。
    Instant now = Instant.now(); // 主机的UTC时间，如果改变系统时间，那么该值也会改变；改变主机时区，该值不变；不同时区获取的值相同；
    System.out.println(now); // 比当前时间晚了8小时
    Instant instant =Instant.ofEpochSecond(10); // 根据秒获取Instant对象；1970-01-01T00:00:10Z（ T表示分隔符,Z表示的是UTC）
    // 判断
    System.out.println(now.isAfter(instant));
    System.out.println(now.isBefore(instant));
    //修改
    now.minusSeconds(1);//减少
    now.plusSeconds(2);//增加

    // ZoneId：时区类；只是代表时区
    Set<String> availableZoneIds = ZoneId.getAvailableZoneIds(); // 一共600个，常用Asia/Shanghai;没有beijing
    ZoneId zoneId = ZoneId.systemDefault(); // 获取系统默认时区；Asia/Shanghai；系统中设置的时区
    ZoneId of = ZoneId.of("America/Cuiaba"); // 获取一个指定时区
    Instant nowTime = Instant.now(); // 不带时区的时间
    ZonedDateTime zonedDateTime = nowTime.atZone(of); // 带时区的时间
    System.out.println(Instant.now().atZone(ZoneId.systemDefault())); // 主机的时间（带时区）

    //ZonedDateTime；带时区的时间对象
    ZonedDateTime now1 = ZonedDateTime.now();//系统当前时间
    ZonedDateTime of1 = ZonedDateTime.of(2023,12,12,12,12,12,12,ZoneId.systemDefault());//获取指定时间
    // 修改
    System.out.println(now1.withYear(2008));//修改时间
    System.out.println(now1.minusDays(1));//减少时间
    System.out.println(now1.plusDays(2));//增加时间
  }
  // 工具类：Period；Duration；ChronoUnit
  // 都是用来计算时间间隔的
  @Test
  void testUtilNew() {
    //Period：计算两个日期间隔（年月日）；年月日分开算间隔
    LocalDate now = LocalDate.now();
    LocalDate of = LocalDate.of(2020,1,1);
    Period between = Period.between(now,of);//第二个参数减第一个参数；of-now
    System.out.println(between.getYears());//-3
    System.out.println(between.getMonths());//-6
    System.out.println(between.getDays());//-9
    System.out.println(between.toTotalMonths());//-42（合计）
    //Duration：计算两个时间间隔（秒，纳秒）；都是合计
    LocalDateTime now1 = LocalDateTime.now();
    LocalDateTime of1 = LocalDateTime.of(2022,1,1,0,0,0);
    Duration between1 = Duration.between(now1,of1);
    System.out.println("-------Duration--------");
    System.out.println(between1.toDays());//转成天；-374
    System.out.println(between1.toHours()); // 转成小时；-8997
    System.out.println(between1.getSeconds()); //获取秒数；-32391890
    // ChronoUnit：计算两个日期间隔（年月日时分秒）；都是合计
    System.out.println("-------ChronoUnit--------");
    System.out.println(ChronoUnit.YEARS.between(now1, of1));//-1
    System.out.println(ChronoUnit.MONTHS.between(now1, of1));//-18
    System.out.println(ChronoUnit.DAYS.between(now1, of1));//-374
    System.out.println(ChronoUnit.HOURS.between(now1, of1));
    System.out.println(ChronoUnit.SECONDS.between(now1, of1));
  }
}
